package com.mingqijia.gassafety.job.job.statistic;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.mingqijia.gassafety.db.entity.CmStatDevice;
import com.mingqijia.gassafety.db.entity.CmStatDevicealarm;
import com.mingqijia.gassafety.db.entity.auth.DictionaryItemEntry;
import com.mingqijia.gassafety.db.entity.vo.DeviceStatByDateVo;
import com.mingqijia.gassafety.db.entity.vo.TotalDeviceNumByDateVo;
import com.mingqijia.gassafety.db.mapper.CmStatDeviceMapper;
import com.mingqijia.gassafety.db.mapper.DtuMapper;
import com.mingqijia.gassafety.db.mapper.auth.DictionaryItemMapper;
import com.mingqijia.gassafety.job.feign.ConsoleSkFeignClient;
import com.mingqijia.gassafety.job.request.ConsoleSkSupplierListRequest;
import com.mingqijia.gassafety.job.response.AlarmSupplierListVo;
import com.mingqijia.gassafety.job.response.ConsoleSkSupplierListResponse;
import com.mingqijia.gassafety.job.service.cmp.EquipmentCmpService;
import com.mingqijia.gassafety.shared.constant.Constants;
import com.mingqijia.gassafety.shared.constant.EquipmentType;
import com.mingqijia.gassafety.shared.utils.RedisCacheExt;
import com.xxl.job.core.biz.model.ReturnT;
import com.xxl.job.core.handler.annotation.XxlJob;
import com.xxl.job.core.log.XxlJobLogger;

import org.apache.commons.collections.CollectionUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;

import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

import cn.hutool.core.date.DateUtil;
import lombok.extern.slf4j.Slf4j;

/**
 * 设备维度统计数据
 * @Author: duanhongxiang
 * @Date: 2024/5/30 12:32
 */
@Configuration
@EnableScheduling
@Slf4j
public class DeviceStatJob {
    @Autowired
    RedisCacheExt redisUtil;

    @Autowired
    DictionaryItemMapper dictionaryItemMapper;

    @Autowired
    CmStatDeviceMapper cmStatDeviceMapper;

    @Autowired
    private EquipmentCmpService equipmentCmpService;

    @Autowired
    DtuMapper dtuMapper;

    @XxlJob("dpDeviceStat")
    //@Scheduled(cron = "* 0/1 * * * ?")
    public ReturnT<String> dpDeviceStat(String param) {
        XxlJobLogger.log("XXLJOB-dpDeviceStat start...");
        log.info("dpDeviceStat--start--------,param:{}",param);
        String key = Constants.CM_STAT_DEVICE;
        try {
            Boolean acquire = redisUtil.setIfAbsent(key, String.valueOf(System.currentTimeMillis()), Constants.TIME_OUT);//15分钟超时
            if (acquire) {
                try {
                    log.info("dpDeviceStat--进入执行器--------");
                    if (execute(param)) {
                        return ReturnT.SUCCESS;
                    } else {
                        return ReturnT.FAIL;
                    }
                } catch (Exception e) {
                    log.info("dpDeviceStat-error:{}", e);
                } finally {
                    redisUtil.del(key);
                }
            }
        } catch (Exception e) {
            log.info("dpDeviceStat-error:{}", e);
        }

        log.info("dpDeviceStat--end--------");
        XxlJobLogger.log("XXLJOB-dpDeviceStat end...");
        return ReturnT.SUCCESS;
    }

    private boolean execute(String param) {
        String statDate;
        if( isValidDate(param) ){
            statDate = param;
        }else{
            LocalDate yesterday = LocalDate.now().minusDays(1);
            statDate = yesterday.format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
        }
        String beginDate = statDate + " 00:00:00";
        String endDate = statDate + " 23:59:59";

        log.info("开始统计开始时间beginDate:{}至endDate:{}的设备数据",beginDate,endDate);

        List<DeviceStatByDateVo> list;
        LambdaQueryWrapper<CmStatDevice> queryCountWrapper = new LambdaQueryWrapper<>();
        queryCountWrapper.eq(CmStatDevice::getUpdateSource, "1");
        if( "all".equals(param) ){
            if( cmStatDeviceMapper.selectCount(queryCountWrapper) >0 ){
                log.info("请清除数据之后再重新刷所有数据");
                XxlJobLogger.log("请清除数据之后再重新刷所有数据");
                return false;
            }
            list =  dtuMapper.selectDeviceStat(endDate);
        }else{
            queryCountWrapper.ge(CmStatDevice::getDataDate, statDate);
            if( cmStatDeviceMapper.selectCount(queryCountWrapper) >0 ){
                log.info("请清除指定日期{}数据之后再重新刷所有数据",statDate);
                XxlJobLogger.log("请清除指定日期"+statDate+"数据之后再重新刷所有数据");
                return false;
            }
            list =  dtuMapper.selectDeviceStatByDate(beginDate,endDate);
        }

        // 查询远程接口，不查字典
        ConsoleSkSupplierListResponse response = equipmentCmpService.supplierListRequest();
        Map<String,String> manufacturerMap = new HashMap<>();
        if (null != response && null != response.getData() && CollectionUtils.isNotEmpty(response.getData()) ) {
            log.info("结束调用厨房查询厂商接口，返回数据长度：{}", response.getData().size());
            manufacturerMap = response.getData().stream()
                    .collect(Collectors.toMap(
                            AlarmSupplierListVo::getAlarmSystemCode,
                            AlarmSupplierListVo::getMsName,
                            (k1, k2) -> k2
                    ));
        }

        if(!ObjectUtils.isEmpty(list)){
            Date currDate = new Date();
            List<CmStatDevice> cmStatDevices = new ArrayList<>();
            for (DeviceStatByDateVo deviceStatByDateVo: list){
                CmStatDevice cmStatDevice = new CmStatDevice();
                BeanUtils.copyProperties(deviceStatByDateVo,cmStatDevice);

                cmStatDevice.setEsName("");
                if( manufacturerMap.containsKey(cmStatDevice.getEsCode()) ){
                    cmStatDevice.setEsName(manufacturerMap.get(cmStatDevice.getEsCode()));
                }

                cmStatDevice.setTypeName(EquipmentType.parse(deviceStatByDateVo.getDeviceType()).getName());

                if( EquipmentType.HOME_GAS_DETECTOR.getCode().equalsIgnoreCase(cmStatDevice.getDeviceType()) ){
                    cmStatDevice.setMyType("1");
                }else{
                    cmStatDevice.setMyType("2");
                }

                cmStatDevice.setTotalDevice(deviceStatByDateVo.getNewDevice());

                String stateDate = DateUtil.format(deviceStatByDateVo.getDataDate(),"yyyy-MM-dd");
                Integer totalDevice = dtuMapper.selectTotalDeviceNumByParam(stateDate +" 23:59:59",
                        deviceStatByDateVo.getSpId(), deviceStatByDateVo.getEsCode(), deviceStatByDateVo.getDeviceType());
                if( null!=totalDevice ){
                    cmStatDevice.setTotalDevice(totalDevice);
                }

                cmStatDevice.setIsSecure("1");
                cmStatDevice.setUpdateSource("1");
                cmStatDevice.setCreateTime(currDate);

                String uuid = UUID.randomUUID().toString();
                cmStatDevice.setId(StringUtils.replace(uuid,"-",""));

                cmStatDevices.add(cmStatDevice);

                if( cmStatDevices.size()>=2 ){
                    cmStatDeviceMapper.insertBatch(cmStatDevices);
                    cmStatDevices.clear();
                    cmStatDevices = new ArrayList<>();
                }
            }
            if( cmStatDevices.size()>0 ){
                cmStatDeviceMapper.insertBatch(cmStatDevices);
            }
        }

        log.info("新增数据处理完成");
        if( !"all".equals(param) ){
            handleUpdatedAtData(beginDate,endDate,manufacturerMap);
            log.info("变更数据处理完成");
        }
        return true;
    }

    private void handleUpdatedAtData(String beginDate,String endDate,Map<String,String> manufacturerMap){
        List<DeviceStatByDateVo> lists = dtuMapper.selectDeviceStatByUpdatedAt(beginDate,endDate);

        log.info("变更数据数量:{}",lists.size());

        for (DeviceStatByDateVo deviceStatByDateVo : lists) {
            String stateDate = DateUtil.format(deviceStatByDateVo.getDataDate(),"yyyy-MM-dd");
            Integer totalDevice = dtuMapper.selectTotalDeviceNumByUpdatedAt(
                    stateDate +" 23:59:59",
                    deviceStatByDateVo.getSpId(),
                    deviceStatByDateVo.getEsCode(),
                    deviceStatByDateVo.getDeviceType()
            );

            List<CmStatDevice> lastDatas = cmStatDeviceMapper.selectLastStatDeviceStatus(
                    deviceStatByDateVo.getSpId(),
                    deviceStatByDateVo.getEsCode(),
                    deviceStatByDateVo.getDeviceType()
            );

            Date currDate = new Date();

            CmStatDevice cmStatDevice = new CmStatDevice();
            LambdaQueryWrapper<CmStatDevice> updateWrapper = new LambdaQueryWrapper<>();
            updateWrapper.eq(CmStatDevice::getSpId, deviceStatByDateVo.getSpId());
            updateWrapper.eq(CmStatDevice::getDataDate, deviceStatByDateVo.getDataDate());
            updateWrapper.eq(CmStatDevice::getEsCode, deviceStatByDateVo.getEsCode());
            updateWrapper.eq(CmStatDevice::getDeviceType, deviceStatByDateVo.getDeviceType());
            updateWrapper.eq(CmStatDevice::getUpdateSource, "1");
            if( null!=lastDatas && lastDatas.size()>0 ){//存在记录
                int compareTo = lastDatas.get(0).getTotalDevice().compareTo(totalDevice);
                if( lastDatas.get(0).getDataDate().getTime() == deviceStatByDateVo.getDataDate().getTime() &&
                        compareTo > 0 ){//当天有记录,且上一条数据总数大于当天数据
                    cmStatDevice.setTotalDevice(totalDevice);
                    cmStatDevice.setUpdateTime(currDate);
                    cmStatDeviceMapper.update(cmStatDevice,updateWrapper);
                }else if( lastDatas.get(0).getDataDate().getTime() == deviceStatByDateVo.getDataDate().getTime() &&
                        compareTo < 0 ){//当天有记录,且上一条数据总数小于当天数据
                    int diff = totalDevice - lastDatas.get(0).getTotalDevice() ;
                    cmStatDevice.setNewDevice(deviceStatByDateVo.getNewDevice()+diff);
                    cmStatDevice.setTotalDevice(totalDevice);
                    cmStatDevice.setUpdateTime(currDate);
                    cmStatDeviceMapper.update(cmStatDevice,updateWrapper);
                }else if( lastDatas.get(0).getDataDate().getTime() < deviceStatByDateVo.getDataDate().getTime() && compareTo != 0){//当天没有记录
                    cmStatDevice.setTotalDevice(totalDevice);
                    int newDevice = 0;
                    if(  compareTo < 0  ){
                        newDevice = totalDevice - lastDatas.get(0).getTotalDevice();
                    }
                    cmStatDevice.setNewDevice(newDevice);
                    createNewDeviceStat(deviceStatByDateVo,manufacturerMap,totalDevice,newDevice);
                }
            }else {//不存在记录，新增记录
                createNewDeviceStat(deviceStatByDateVo,manufacturerMap,totalDevice,totalDevice);
            }
        }
    }

    private void createNewDeviceStat(DeviceStatByDateVo deviceStatByDateVo,
                                     Map<String,String> manufacturerMap,
                                     Integer totalDevice,
                                     Integer newDevice){
        CmStatDevice cmStatDevice = new CmStatDevice();
        BeanUtils.copyProperties(deviceStatByDateVo,cmStatDevice);

        cmStatDevice.setEsName("");
        if( manufacturerMap.containsKey(cmStatDevice.getEsCode()) ){
            cmStatDevice.setEsName(manufacturerMap.get(cmStatDevice.getEsCode()));
        }

        cmStatDevice.setTypeName(EquipmentType.parse(deviceStatByDateVo.getDeviceType()).getName());

        if( EquipmentType.HOME_GAS_DETECTOR.getCode().equalsIgnoreCase(cmStatDevice.getDeviceType()) ){
            cmStatDevice.setMyType("1");
        }else{
            cmStatDevice.setMyType("2");
        }

        cmStatDevice.setTotalDevice(totalDevice);
        cmStatDevice.setNewDevice(newDevice);

        cmStatDevice.setUpdateSource("1");
        cmStatDevice.setIsSecure("1");

        String uuid = UUID.randomUUID().toString();
        cmStatDevice.setId(StringUtils.replace(uuid,"-",""));

        cmStatDevice.setCreateTime(new Date());
        cmStatDeviceMapper.insert(cmStatDevice);
    }

    private String getParamKey(DeviceStatByDateVo deviceStatByDateVo){
        return deviceStatByDateVo.getDataDate()+"-"+deviceStatByDateVo.getSpId()
                +"-"+deviceStatByDateVo.getEsCode()+"-"+deviceStatByDateVo.getDeviceType();
    }

    private boolean isValidDate(String date) {
        String regex = "^\\d{4}-\\d{2}-\\d{2}$";
        Pattern pattern = Pattern.compile(regex);
        Matcher matcher = pattern.matcher(date);
        return matcher.matches();
    }
}
